bitkeeper revision 1.1159.261.1 (420e14ceCymFrPEpDCTaPJueMUTvsg)
authormafetter@fleming.research <mafetter@fleming.research>
Sat, 12 Feb 2005 14:38:06 +0000 (14:38 +0000)
committermafetter@fleming.research <mafetter@fleming.research>
Sat, 12 Feb 2005 14:38:06 +0000 (14:38 +0000)
Improved check_pagetable checking.
Added check_all_pagetables as an alternative to check_pagetable().

xen/arch/x86/shadow.c
xen/include/asm-x86/shadow.h
xen/include/xen/perfc_defn.h

index 70ad4be686caacbbad39f1a34b87fa4bd407920c..1131ab5e200930c5b5937f768b41ca011e0491f7 100644 (file)
@@ -758,10 +758,10 @@ void shadow_l2_normal_pt_update(unsigned long pa, unsigned long gpde)
 // BUG: these are not SMP safe...
 static int sh_l2_present;
 static int sh_l1_present;
-static int errors;
 char * sh_check_name;
+int shadow_status_noswap;
 
-#define virt_to_phys2(adr) ({                                            \
+#define v2m(adr) ({                                                      \
     unsigned long _a = (unsigned long)(adr);                             \
     unsigned long _pte = l1_pgentry_val(                                 \
                             shadow_linear_pg_table[_a >> PAGE_SHIFT]);   \
@@ -771,23 +771,28 @@ char * sh_check_name;
 
 #define FAIL(_f, _a...)                                                      \
     do {                                                                     \
-        printk("XXX %s-FAIL (%d,%d)" _f " g=%p s=%p &g=%p &s=%p" \
-               " pa(&g)=%p pa(&s)=%p\n",                               \
-               sh_check_name, level, i, ## _a , gpte, spte, pgpte, pspte,    \
-               virt_to_phys2(pgpte), virt_to_phys2(pspte));                  \
+        printk("XXX %s-FAIL (%d,%d)" _f "\n"                                 \
+               "g=%08lx s=%08lx &g=%08lx &s=%08lx"                           \
+               " v2m(&g)=%08lx v2m(&s)=%08lx ea=%08lx\n",                    \
+               sh_check_name, level, l1_idx, ## _a ,                         \
+               gpte, spte, pgpte, pspte,                                     \
+               v2m(pgpte), v2m(pspte),                                       \
+               (l2_idx << L2_PAGETABLE_SHIFT) |                              \
+               (l1_idx << L1_PAGETABLE_SHIFT));                              \
         errors++;                                                            \
     } while ( 0 )
 
 static int check_pte(
     struct domain *d, unsigned long *pgpte, unsigned long *pspte, 
-    int level, int i)
+    int level, int l2_idx, int l1_idx)
 {
     unsigned gpte = *pgpte;
     unsigned spte = *pspte;
     unsigned long mask, gpfn, smfn;
+    int errors = 0;
 
     if ( (spte == 0) || (spte == 0xdeadface) || (spte == 0x00000E00) )
-        return 1;  /* always safe */
+        return errors;  /* always safe */
 
     if ( !(spte & _PAGE_PRESENT) )
         FAIL("Non zero not present spte");
@@ -833,72 +838,71 @@ static int check_pte(
                  __shadow_status(d, gpfn) );
     }
 
-    return 1;
+    return errors;
 }
 
 
 static int check_l1_table(
     struct domain *d,
-    unsigned long g2mfn, unsigned long s2mfn)
+    unsigned long gmfn, unsigned long smfn, unsigned l2_idx)
 {
     int i;
     unsigned long *gpl1e, *spl1e;
+    int cpu = current->processor;
+    int errors = 0;
+
+    // First check to see if this guest page is currently the active
+    // PTWR page.  If so, then we compare the (old) cached copy of the
+    // guest page to the shadow, and not the currently writable (and
+    // thus potentially out-of-sync) guest page.
+    //
+    if ( VM_ASSIST(d, VMASST_TYPE_writable_pagetables) )
+    {
+        for ( i = 0; i < ARRAY_SIZE(ptwr_info->ptinfo); i++)
+        {
+            if ( ptwr_info[cpu].ptinfo[i].l1va &&
+                 ((v2m(ptwr_info[cpu].ptinfo[i].pl1e) >> PAGE_SHIFT) == gmfn) )
+            {
+                unsigned long old = gmfn;
+                gmfn = (v2m(ptwr_info[cpu].ptinfo[i].page) >> PAGE_SHIFT);
+                printk("hit1 ptwr_info[%d].ptinfo[%d].l1va, mfn=0x%08x, snapshot=0x%08x\n",
+                       cpu, i, old, gmfn);
+            }
+        }
+    }
 
-    gpl1e = map_domain_mem(g2mfn << PAGE_SHIFT);
-    spl1e = map_domain_mem(s2mfn << PAGE_SHIFT);
+    gpl1e = map_domain_mem(gmfn << PAGE_SHIFT);
+    spl1e = map_domain_mem(smfn << PAGE_SHIFT);
 
     for ( i = 0; i < ENTRIES_PER_L1_PAGETABLE; i++ )
-        check_pte(d, &gpl1e[i], &spl1e[i], 1, i);
+        errors += check_pte(d, &gpl1e[i], &spl1e[i], 1, l2_idx, i);
  
     unmap_domain_mem(spl1e);
     unmap_domain_mem(gpl1e);
 
-    return 1;
+    return errors;
 }
 
-#define FAILPT(_f, _a...)                                      \
-    do {                                                       \
-        printk("XXX FAIL %s-PT" _f "\n", s, ## _a );           \
-        errors++;                                              \
+#define FAILPT(_f, _a...)                                         \
+    do {                                                          \
+        printk("XXX FAIL %s-PT " _f "\n", sh_check_name, ## _a ); \
+        errors++;                                                 \
     } while ( 0 )
 
-void check_pagetable(struct domain *d, pagetable_t pt, char *s)
+int check_l2_table(
+    struct domain *d, unsigned long gpfn, unsigned long smfn)
 {
-    unsigned long gptbase = pagetable_val(pt);
-    unsigned long ptbase_pfn, smfn, ss;
-    unsigned long i;
-    l2_pgentry_t *gpl2e, *spl2e;
-    unsigned long ptbase_mfn = 0;
-    int cpu = current->processor;
-
-    errors = 0;
-    sh_check_name = s;
-
-    SH_VVLOG("%s-PT Audit", s);
-
-    sh_l2_present = sh_l1_present = 0;
-
-    ptbase_pfn = gptbase >> PAGE_SHIFT;
-    ptbase_mfn = __gpfn_to_mfn(d, ptbase_pfn);
-
-    ss = __shadow_status(d, ptbase_pfn);
-  
-    if ( ! (ss & PSH_shadowed) )
-    {
-        printk("%s-PT %p not shadowed\n", s, gptbase);
-
-        if ( ss != 0 )
-            BUG();
-        return;
-    }   
-    smfn = ss & PSH_pfn_mask;
-
-    if ( ss != (PSH_shadowed | smfn) )
-        FAILPT("ptbase shadow inconsistent1");
+    unsigned long gmfn = __gpfn_to_mfn(d, gpfn);
+    l2_pgentry_t *gpl2e = (l2_pgentry_t *) map_domain_mem( gmfn << PAGE_SHIFT );
+    l2_pgentry_t *spl2e = (l2_pgentry_t *) map_domain_mem( smfn << PAGE_SHIFT );
+    int i;
+    int errors = 0;
 
-    gpl2e = (l2_pgentry_t *) map_domain_mem( ptbase_mfn << PAGE_SHIFT );
-    spl2e = (l2_pgentry_t *) map_domain_mem( smfn << PAGE_SHIFT );
+    if ( page_get_owner(pfn_to_page(gmfn)) != d )
+        FAILPT("domain doesn't own page");
+    if ( page_get_owner(pfn_to_page(smfn)) != NULL )
+        FAILPT("shadow page mfn=0x%08x is owned by someone, domid=%d",
+               smfn, page_get_owner(pfn_to_page(smfn))->id);
 
     if ( memcmp(&spl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE],
                 &gpl2e[DOMAIN_ENTRIES_PER_L2_PAGETABLE], 
@@ -918,24 +922,68 @@ void check_pagetable(struct domain *d, pagetable_t pt, char *s)
         FAILPT("hypervisor linear map inconsistent");
 
     if ( (l2_pgentry_val(spl2e[SH_LINEAR_PT_VIRT_START >> 
-                              L2_PAGETABLE_SHIFT]) != 
+                               L2_PAGETABLE_SHIFT]) != 
           ((smfn << PAGE_SHIFT) | __PAGE_HYPERVISOR)) )
         FAILPT("hypervisor shadow linear map inconsistent %p %p",
                l2_pgentry_val(spl2e[SH_LINEAR_PT_VIRT_START >>
-                                   L2_PAGETABLE_SHIFT]),
+                                    L2_PAGETABLE_SHIFT]),
                (smfn << PAGE_SHIFT) | __PAGE_HYPERVISOR);
 
     if ( shadow_mode(d) != SHM_full_32 ) {
-        // BUG: this shouldn't be using exec_domain[0] here...
         if ( (l2_pgentry_val(spl2e[PERDOMAIN_VIRT_START >> L2_PAGETABLE_SHIFT]) !=
-              ((__pa(page_get_owner(&frame_table[ptbase_pfn])->arch.mm_perdomain_pt) | 
-            __PAGE_HYPERVISOR))) )
+              ((v2m(page_get_owner(&frame_table[gmfn])->arch.mm_perdomain_pt) |
+                __PAGE_HYPERVISOR))) )
             FAILPT("hypervisor per-domain map inconsistent");
     }
 
     /* Check the whole L2. */
     for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
-        check_pte(d, &l2_pgentry_val(gpl2e[i]), &l2_pgentry_val(spl2e[i]), 2, i);
+        errors += check_pte(d, &l2_pgentry_val(gpl2e[i]), &l2_pgentry_val(spl2e[i]), 2, i, 0);
+
+    unmap_domain_mem(spl2e);
+    unmap_domain_mem(gpl2e);
+
+    return errors;
+}
+
+int _check_pagetable(struct domain *d, pagetable_t pt, char *s)
+{
+    unsigned long gptbase = pagetable_val(pt);
+    unsigned long ptbase_pfn, smfn, ss;
+    unsigned long i;
+    l2_pgentry_t *gpl2e, *spl2e;
+    unsigned long ptbase_mfn = 0;
+    int errors = 0;
+
+    sh_check_name = s;
+    SH_VVLOG("%s-PT Audit", s);
+    sh_l2_present = sh_l1_present = 0;
+    perfc_incrc(check_pagetable);
+
+    ptbase_pfn = gptbase >> PAGE_SHIFT;
+    ptbase_mfn = __gpfn_to_mfn(d, ptbase_pfn);
+
+    ss = __shadow_status(d, ptbase_pfn);
+  
+    if ( ! (ss & PSH_shadowed) )
+    {
+        printk("%s-PT %p not shadowed\n", s, gptbase);
+        errors++;
+
+        if ( ss != 0 )
+            BUG();
+        return errors;
+    }   
+    smfn = ss & PSH_pfn_mask;
+
+    if ( ss != (PSH_shadowed | smfn) )
+        FAILPT("ptbase shadow inconsistent1");
+
+    errors += check_l2_table(d, ptbase_pfn, smfn);
+
+    gpl2e = (l2_pgentry_t *) map_domain_mem( ptbase_mfn << PAGE_SHIFT );
+    spl2e = (l2_pgentry_t *) map_domain_mem( smfn << PAGE_SHIFT );
 
     /* Go back and recurse. */
     for ( i = 0; i < DOMAIN_ENTRIES_PER_L2_PAGETABLE; i++ )
@@ -946,20 +994,7 @@ void check_pagetable(struct domain *d, pagetable_t pt, char *s)
 
         if ( l2_pgentry_val(spl2e[i]) != 0 )
         {
-            // First check to see if this guest page is currently the active
-            // PTWR page.  If so, then we compare the (old) cached copy of the
-            // guest page to the shadow, and not the currently writable (and
-            // thus potentially out-of-sync) guest page.
-            //
-            if ( ptwr_info[cpu].ptinfo[PTWR_PT_ACTIVE].l1va &&
-                 (i == ptwr_info[cpu].ptinfo[PTWR_PT_ACTIVE].l2_idx) &&
-                 likely(VM_ASSIST(d, VMASST_TYPE_writable_pagetables)) )
-            {
-                gl1mfn = (__pa(ptwr_info[cpu].ptinfo[PTWR_PT_ACTIVE].page) >>
-                          PAGE_SHIFT);
-            }
-
-            check_l1_table(d, gl1mfn, sl1mfn);
+            errors += check_l1_table(d, gl1mfn, sl1mfn, i);
         }
     }
 
@@ -969,10 +1004,104 @@ void check_pagetable(struct domain *d, pagetable_t pt, char *s)
     SH_VVLOG("PT verified : l2_present = %d, l1_present = %d",
              sh_l2_present, sh_l1_present);
  
+#if 1
+    if ( errors )
+        BUG();
+#endif
+
+    return errors;
+}
+
+int _check_all_pagetables(struct domain *d, char *s)
+{
+    int i, j;
+    struct shadow_status *a;
+    unsigned long gmfn;
+    int errors = 0;
+    int cpu;
+
+    shadow_status_noswap = 1;
+
+    sh_check_name = s;
+    SH_VVLOG("%s-PT Audit domid=%d", s, d->id);
+    sh_l2_present = sh_l1_present = 0;
+    perfc_incrc(check_all_pagetables);
+
+    for (i = 0; i < shadow_ht_buckets; i++)
+    {
+        a = &d->arch.shadow_ht[i];
+        while ( a && a->pfn )
+        {
+            gmfn = __gpfn_to_mfn(d, a->pfn);
+            switch ( frame_table[a->pfn].u.inuse.type_info & PGT_type_mask )
+            {
+            case PGT_l1_page_table:
+                errors += check_l1_table(d, gmfn, a->smfn_and_flags & PSH_pfn_mask, 0);
+                break;
+            case PGT_l2_page_table:
+                errors += check_l2_table(d, gmfn, a->smfn_and_flags & PSH_pfn_mask);
+                break;
+            default:
+                errors++;
+                printk("unexpected page type 0x%08x, pfn=0x%08x, gmfn=0x%08x\n",
+                       frame_table[gmfn].u.inuse.type_info,
+                       a->pfn, gmfn);
+                BUG();
+            }
+            a = a->next;
+        }
+    }
+
+    shadow_status_noswap = 0;
+
+    for (i = 0; i < 1024; i++)
+    {
+        if ( l2_pgentry_val(shadow_linear_l2_table[i]) & _PAGE_PRESENT )
+        {
+            unsigned base = i << 10;
+            for (j = 0; j < 1024; j++)
+            {
+                if ( (l1_pgentry_val(shadow_linear_pg_table[base + j]) & PAGE_MASK) == 0x0143d000 )
+                {
+                    printk("sh_ln_pg_tb[0x%08x] => 0x%08lx ",
+                           base + j,
+                           l1_pgentry_val(shadow_linear_pg_table[base + j]));
+                    if ( l1_pgentry_val(shadow_linear_pg_table[base + j]) & _PAGE_PRESENT )
+                        printk(" first entry => 0x%08lx\n",
+                               *(unsigned long *)((base + j) << PAGE_SHIFT));
+                    else
+                        printk(" page not present\n");
+                }
+            }
+        }
+    }
+
     if ( errors )
+    {
+        printk("VM_ASSIST(d, VMASST_TYPE_writable_pagetables) => %d\n",
+               VM_ASSIST(d, VMASST_TYPE_writable_pagetables));
+        for ( cpu = 0; cpu < smp_num_cpus; cpu++ )
+        {
+            for ( j = 0; j < ARRAY_SIZE(ptwr_info->ptinfo); j++)
+            {
+                printk("ptwr_info[%d].ptinfo[%d].l1va => 0x%08x\n",
+                       cpu, j, ptwr_info[cpu].ptinfo[j].l1va);
+                printk("ptwr_info[%d].ptinfo[%d].pl1e => 0x%08x\n",
+                       cpu, j, ptwr_info[cpu].ptinfo[j].pl1e);
+                if (cpu == smp_processor_id())
+                    printk("v2m(ptwr_info[%d].ptinfo[%d].pl1e) => 0x%08x\n",
+                           cpu, j, v2m(ptwr_info[cpu].ptinfo[j].pl1e));
+                printk("ptwr_info[%d].ptinfo[%d].page => 0x%08x\n",
+                       cpu, j, ptwr_info[cpu].ptinfo[j].page);
+                if (cpu == smp_processor_id())
+                    printk("v2m(ptwr_info[%d].ptinfo[%d].page) => 0x%08x\n",
+                           cpu, j, v2m(ptwr_info[cpu].ptinfo[j].page));
+            }
+        }
         BUG();
+    }
 
-    return;
+    return errors;
 }
 
 #endif // SHADOW_DEBUG
index 7618c610f2be23f81f3a62c1236f6a81e43c330d..5719f2ef100a210205f69fc324181d6df609438b 100644 (file)
@@ -73,9 +73,13 @@ static inline void shadow_invalidate(struct exec_domain *ed) {
     memset(ed->arch.shadow_vtable, 0, PAGE_SIZE);
 }
 
-#define SHADOW_DEBUG 1
+#define SHADOW_DEBUG 0
 #define SHADOW_VERBOSE_DEBUG 0
-#define SHADOW_HASH_DEBUG 1
+#define SHADOW_HASH_DEBUG 0
+
+#if SHADOW_DEBUG
+extern int shadow_status_noswap;
+#endif
 
 struct shadow_status {
     unsigned long pfn;            /* Guest pfn.             */
@@ -88,7 +92,7 @@ struct shadow_status {
 
 #ifdef VERBOSE
 #define SH_LOG(_f, _a...)                                               \
-printk("DOM%uP%u: (file=shadow.c, line=%d) " _f "\n",                   \
+    printk("DOM%uP%u: SH_LOG(%d): " _f "\n",                            \
        current->domain->id , current->processor, __LINE__ , ## _a )
 #else
 #define SH_LOG(_f, _a...) 
@@ -96,7 +100,7 @@ printk("DOM%uP%u: (file=shadow.c, line=%d) " _f "\n",                   \
 
 #if SHADOW_DEBUG
 #define SH_VLOG(_f, _a...)                                              \
-    printk("DOM%uP%u: (file=shadow.c, line=%d) " _f "\n",               \
+    printk("DOM%uP%u: SH_VLOG(%d): " _f "\n",                           \
            current->domain->id, current->processor, __LINE__ , ## _a )
 #else
 #define SH_VLOG(_f, _a...) 
@@ -104,7 +108,7 @@ printk("DOM%uP%u: (file=shadow.c, line=%d) " _f "\n",                   \
 
 #if SHADOW_VERBOSE_DEBUG
 #define SH_VVLOG(_f, _a...)                                             \
-    printk("DOM%uP%u: (file=shadow.c, line=%d) " _f "\n",               \
+    printk("DOM%uP%u: SH_VVLOG(%d): " _f "\n",                          \
            current->domain->id, current->processor, __LINE__ , ## _a )
 #else
 #define SH_VVLOG(_f, _a...)
@@ -426,6 +430,10 @@ static inline unsigned long __shadow_status(
 
         if ( x->pfn == gpfn )
         {
+#if SHADOW_DEBUG
+            if ( unlikely(shadow_status_noswap) )
+                return x->smfn_and_flags;
+#endif
             /* Pull-to-front if 'x' isn't already the head item. */
             if ( unlikely(x != head) )
             {
@@ -726,9 +734,14 @@ static inline void shadow_mk_pagetable(struct exec_domain *ed)
 }
 
 #if SHADOW_DEBUG
-extern void check_pagetable(struct domain *d, pagetable_t pt, char *s);
+extern int _check_pagetable(struct domain *d, pagetable_t pt, char *s);
+extern int _check_all_pagetables(struct domain *d, char *s);
+
+#define check_pagetable(_d, _pt, _s) _check_pagetable(_d, _pt, _s)
+//#define check_pagetable(_d, _pt, _s) _check_all_pagetables(_d, _s)
+
 #else
-#define check_pagetable(d, pt, s) ((void)0)
+#define check_pagetable(_d, _pt, _s) ((void)0)
 #endif
 
 #endif /* XEN_SHADOW_H */
index f6868d78b988f8292bbcbafa74c04b6b2f9b64c0..90c7731fac68cf2aa1506fdfdd2581afc2a1bc31 100644 (file)
@@ -30,3 +30,6 @@ PERFCOUNTER_CPU( shadow_update_va_fail, "shadow_update_va_fail" )
 /* STATUS counters do not reset when 'P' is hit */
 PERFSTATUS( shadow_l2_pages, "current # shadow L2 pages" )
 PERFSTATUS( shadow_l1_pages, "current # shadow L1 pages" )
+
+PERFCOUNTER_CPU( check_pagetable, "calls to check_pagetable" )
+PERFCOUNTER_CPU( check_all_pagetables, "calls to check_all_pagetables" )